use crossterm::cursor::{Hide, MoveTo, Show};
use crossterm::style::Print;
use crossterm::terminal::{disable_raw_mode, enable_raw_mode, Clear};
use crossterm::{queue, terminal, Command};
use std::io::{stdout, Error, Write};

pub struct Terminal;
impl Terminal {
    pub fn initialize() -> Result<(), Error> {
        enable_raw_mode()?;
        Self::clean_screen()?;
        Self::move_caret(Position::top_left())?;
        Self::execute()
    }

    pub fn terminate() -> Result<(), Error> {
        disable_raw_mode()
    }

    pub fn size() -> Result<Size, Error> {
         Size::terminal_size()
    }

    // fn move_cursor_to_lefttop()->Result<(),Error>{
    //     execute!(stdout(),MoveTo(0x0,0x0),EnableBlinking,cursor::SetCursorStyle::BlinkingUnderScore)
    // }

    pub fn hiden_caret() -> Result<(), Error> {
        Self::queue_command(Hide)
    }
    pub fn show_caret() -> Result<(), Error> {
        Self::queue_command(Show)
    }
    pub fn move_caret(p: Position) -> Result<(), Error> {
        Self::queue_command(MoveTo(p.col as u16, p.row as u16))
    }
    pub fn print(s: &str) -> Result<(), Error> {
        Self::queue_command(Print(s))
    }
    pub fn print_c(c: &char) -> Result<(), Error> {
        Self::queue_command(Print(c))
    }
    pub fn execute() -> Result<(), Error> {
        stdout().flush()
    }
    pub fn clean_screen() -> Result<(), Error> {
        Self::queue_command(Clear(crossterm::terminal::ClearType::All))
    }
    pub fn clear_line() -> Result<(), Error> {
        Self::queue_command(Clear(crossterm::terminal::ClearType::CurrentLine))
    }
    pub fn queue_command<T:Command>(command:T)->Result<(),Error>{
        queue!(stdout(),command)
    }
}
#[derive(Default)]
pub struct Position {
    pub col: usize,
    pub row: usize,
}

impl Position {
    pub const fn top_left() -> Self {
        Self { col: 0, row: 0 }
    }
}
pub struct Size {
    pub width: usize,
    pub height: usize,
}
impl Size {
    pub fn terminal_size() -> Result<Self,Error> {
        let s = terminal::size()?;
        Ok(Self {
            width: s.0 as usize,
            height: s.1 as usize,
        })
    }
}
